import DomHelper from '../domHelper';
import { MeshHelper, StereoHelper } from '../../stereoHelper';
import tool from '../../../../../../utils/tool';
import { NO_PICTURE_SRC } from '../../../../../../utils/consts'

export default {
    canvasCreator(opts) {
        let widget = opts.data;
        let containerWidth = opts.containerWidth || widget.width,
            containerHeight = opts.containerHeight || widget.height;
        let gradientWidth = opts.gradientWidth || widget.width,
            gradientHeight = opts.gradientHeight || widget.height;

        let canvas = document.createElement("canvas");
        canvas.width = containerWidth;
        canvas.height = containerHeight;

        let ctx = canvas.getContext("2d");

        // 画圆角矩形
        this.drawRoundRect(ctx, 0, 0, containerWidth, containerHeight, widget.radius || 1);

        ctx.globalAlpha = opts.alpha == undefined ? 1 : opts.alpha;

        if (opts.gradientParam) {
            // 绘制渐变背景色
            this.fillWithGradient(widget, ctx, gradientWidth, gradientHeight, opts.gradientParam);
            // 绘制2d模型右侧状态区域
            this.fillStateRegion(widget, ctx);
        } else {
            ctx.fillStyle = "#" + widget.color;
            ctx.fill();
        }

        opts.imgFn && opts.imgFn.call(this, canvas);
        opts.textFn && opts.textFn.call(this, canvas);

        return canvas;
    },

    // 绘制圆角矩形
    drawRoundRect(context, x, y, w, h, r) {
        let minSize = Math.min(w, h);
        if (r > minSize / 2) {
            r = minSize / 2;
        }

        // 开始绘制
        context.beginPath();
        context.moveTo(x + r, y);
        context.arcTo(x + w, y, x + w, y + h, r);
        context.arcTo(x + w, y + h, x, y + h, r);
        context.arcTo(x, y + h, x, y, r);
        context.arcTo(x, y, x + w, y, r);
        context.closePath();

        return context;
    },

    fillWithGradient(widget, ctx, gradientWidth, gradientHeight, gradientParam) {
        // 设置渐变背景色
        let gradient = ctx.createLinearGradient(0, 0, gradientWidth, gradientHeight);

        gradient.addColorStop(0, "rgb(" + gradientParam.R + "," + gradientParam.G + "," + gradientParam.B + ")");
        gradient.addColorStop(1, "#" + widget.color);

        ctx.fillStyle = gradient;
        ctx.fill();
    },

    fillStateRegion(widget, ctx) {
        let stateTypes = ["threed"];
        if ($.inArray(widget.stereoType, stateTypes) != -1) {
            ctx.fillStyle = widget.stateBackground;
            ctx.fillRect(widget.width, 0, widget.stateWidth, widget.stateHeight);

            ctx.strokeStyle = widget.stateStroke;
            ctx.strokeRect(widget.width, 0, widget.stateWidth, widget.stateHeight);
        }
    },

    // 渐变材质创建器
    gradientMaterialCreator: function(widget) {
        let gradColor = tool.converionColor(widget.color);
        let canvas = this.canvasCreator({
            data: widget,
            gradientParam: gradColor
        });

        let texture = new THREE.CanvasTexture(canvas);
        let material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide, transparent: true, opacity: widget.opacity });
        return material;
    },

    // 渐变图形创建器
    gradientMeshCreator: function(widget) {
        let geometry = new THREE.PlaneGeometry(widget.width, widget.height);
        let material = this.gradientMaterialCreator(widget);
        let mesh = this.meshCreator(null, THREE.PlaneGeometry, {}, widget, geometry, material);
        return mesh;
    },

    //3D图形生成器
    meshCreator: function(localMesh, Type, param, data, geometry, material) {
        let _geometry = geometry ? geometry : new Type(data.width, data.height, 1, 1);
        let _material = material ? material : new THREE.MeshBasicMaterial(param);

        let mesh = localMesh ? localMesh : new THREE.Mesh(_geometry, _material);
        mesh.position.set(data.offset_x, data.offset_y, data.offset_z);

        mesh.rotation.set(data.stereoRotateX, data.stereoRotateY, data.stereoRotateZ);

        mesh.data = data;
        if (!data.nonSelectable) {
            MeshHelper.addMesh(mesh);
            // 添加组件后自动选中，与2d中同步
            if (data.fromAdd) {
                delete data.fromAdd;
                this.selectedMesh(mesh);
            }
        } else {
            DomHelper.mainImgMesh = mesh;
        }

        // 切换显示/隐藏属性
        mesh.visible = data.visible;

        return mesh;
    },
    // 预加载图片贴图
    preloadImage(url, widget, isUpdate, isFirstLoad, isMainImg) {
        let params = {
            transparent: !isMainImg,
            side: THREE.DoubleSide,
            opacity: widget.opacity
        };

        let preloadUrl = isFirstLoad ? NO_PICTURE_SRC : url;
        this.specifyLoaderMaterial(THREE.TextureLoader, preloadUrl, function(texture) {
            params["map"] = texture;
            if (isUpdate) {
                let material = new THREE.MeshBasicMaterial(params);
                let meshItem = isMainImg ? DomHelper.mainImgMesh : MeshHelper.getMeshById(widget.id);
                if (meshItem) {
                    meshItem.material = material;
                }
            } else {
                let mesh = this.meshCreator(null, THREE.PlaneGeometry, params, widget);
                DomHelper.scene.add(mesh);
            }
            if (isFirstLoad) {
                this.preloadImage(url, widget, true, false, isMainImg);
            }

            // me.reRender();
            DomHelper.renderer.render(DomHelper.scene, DomHelper.camera);
        });
    },

    /**
     * 指定加载器
     */
    specifyLoaderMaterial(Type, url, fn) {
        let loader = new Type();
        loader.load(url, function(data) {
            fn.call(this, data);
        }.bind(this));
    },

    /**
     * 图片加载器
     */
    specifyImageLoader: function(data, fn) {
        if (data.icon || data.icon_class) {
            let img = new Image();
            img.onload = function() {
                fn && fn.call(this, data);
            };
            img.src = data.stereoUrl || "";
        } else {
            fn && fn.call(this, data);
        }
    },

    imageGeometryLoader(url, widget, isUpdate, isMainImg) {
        let src = url || widget.url;
        if (src) {
            this.preloadImage(src, widget, isUpdate, true, isMainImg);
        }
    },

    selectedMesh(mesh) {
        this.attachItem(mesh.object ? mesh.object : mesh);
    },

    attachItem(mesh) {
        // 选中时重新销毁和创建TransformControls来修复方向轴被图形覆盖的问题
        this.destroyTransformControls();
        this.initTransformControls();

        DomHelper.selectedMeshId = mesh.data.id;
        DomHelper.selectedItem = mesh;
        DomHelper.transformControls.attach(mesh);

        this.changeTransformType(DomHelper.transformType);
    },

    changeTransformType(type) {
        if (type && DomHelper.selectedItem instanceof THREE.Mesh) {
            DomHelper.transformControls.setMode(type);
            // 修改stereoEditbar的选中状态
            DomHelper.currentTransformBar.addClass('hover').siblings('li').removeClass('hover');
        }
    },

    initTransformControls() {
        let that = this;
        DomHelper.transformControls = new THREE.TransformControls(DomHelper.camera, DomHelper.renderer.domElement);
        DomHelper.scene.add(DomHelper.transformControls);
        DomHelper.transformControls.addEventListener("change", ()=>this.handleOnTransformChanged(), false);       
    },

    initOrbitControls() {
        DomHelper.orbitControls = new THREE.OrbitControls(DomHelper.camera, DomHelper.renderer.domElement);
        // 禁止使用方向键
        DomHelper.orbitControls.noKeys = true;
    },

    initControls() {
        let that = this;
        DomHelper.ready(() => {
            that.initTransformControls();
            that.initOrbitControls();
        })            
    },

    destroyTransformControls() {
        DomHelper.transformControls.detach();
        DomHelper.scene.remove(DomHelper.transformControls);
        DomHelper.transformControls = null;
    },

    detachItem() {
        DomHelper.selectedItem = {};
        DomHelper.selectedMeshId = 0;
        DomHelper.transformControls.detach();
    },

    handleOnTransformChanged() {
        let mode = DomHelper.transformControls.getMode();
        if (DomHelper.selectedItem.data){
            switch (mode){
                case "translate":
                    StereoHelper.translateData(DomHelper.selectedItem);

                    break;
                case "rotate":
                    StereoHelper.rotateData(DomHelper.selectedItem);
                    break;
                case "scale":
                    StereoHelper.scaleData(DomHelper.selectedItem);
                    break;
            }
            DomHelper.selectedMeshId = DomHelper.selectedItem.data.id;
            DomHelper.updateWidget(DomHelper.selectedItem.data)
        }
    },

    // 即时修改素材属性，包括选中和未选中的
    resetMeshItem(data, resetFunc = null) {
        let type = data.type;
        if (data && !tool.isEmptyObject(data)){

            if (DomHelper.selectedItem instanceof THREE.Mesh){
                DomHelper.selectedItem.data = data;

                // 调整透明度
                DomHelper.selectedItem.material.opacity = data.opacity;

                // 调整位置
                DomHelper.selectedItem.position && DomHelper.selectedItem.position.set(data.offset_x, data.offset_y, data.offset_z);

                // 角度转弧度
                DomHelper.selectedItem.rotation && DomHelper.selectedItem.rotation.set(data.stereoRotateX, data.stereoRotateY, data.stereoRotateZ);

                // 优化性能，调整大小
                if (data.sizeChanged || data.pictureChanged){
                    delete data.sizeChanged;
                    delete data.pictureChanged;

                    DomHelper.selectedItem.geometry = new THREE.PlaneGeometry(data.width, data.height, 1, 1);
                }
            // 没有图形被选中情况下获取对应图形并更新数据
            } else {
                let mesh = MeshHelper.getMeshById(data.id);
                if (mesh){
                    mesh.data = data;
                }
            }

            if (data.propertyChanged){
                delete data.propertyChanged;
                resetFunc && resetFunc(data)
            }

            StereoHelper.updateStereo(data);
        }
    }
}
